﻿using System;
using System.Collections;
using System.Runtime.InteropServices;
using OFX.Aggregator.Infrastructure;

namespace OFX.Aggregator.WebScraping.Infrastructure
{
	public class WebStatementRetrieval : IAsyncStatementRetrieval
	{
		private readonly string asyncResultServiceId;
		private readonly IStatementInterpreter interpreter;

		public WebStatementRetrieval(string asyncResultServiceId, IStatementInterpreter interpreter)
		{
			this.asyncResultServiceId = asyncResultServiceId;
			this.interpreter = interpreter;
		}

		#region Implementation of IStatementRetrieval

		public bool CanRetrieveStatement
		{
			get
			{
				uint flags = 0;
				return InternetGetConnectedState(ref flags, 0);
			}
		}

		public Statement GetStatement(DateTime? dateStart, DateTime? dateEnd)
		{
			throw new NotImplementedException();
		}

		#region Implementation of IAsyncStatementRetrieval

		public IAsyncResult BeginGetStatement(IIoCContainerAbstraction container,
		                                      IStatementProcessingWorkflow workflow,
		                                      AsyncCallback callback)
		{
			IDictionary parameters = new Hashtable
			                         	{
			                         		{"workflow", workflow},
			                         		{"callback", callback},
			                         	};

			var asyncResult = container.Resolve<WebStatementRetrievalAsyncResult>(this.asyncResultServiceId, parameters);

			return asyncResult;
		}

		public Statement EndGetStatement(IAsyncResult result)
		{
			var asyncResult = (WebStatementRetrievalAsyncResult) result;
			asyncResult.AsyncWaitHandle.WaitOne();

			Exception ex = asyncResult.Exception;

			((IDisposable) asyncResult).Dispose();

			if (ex == null)
			{
				Statement statement = this.interpreter.InterpretStatement(asyncResult.ResultHtml);

				if (statement != null)
				{
					StatementFilter.Filter(statement, asyncResult.DateStart, asyncResult.DateEnd);
				}

				return statement;
			}

			throw new Exception("Failed to retrieve statement! See inner exception.", ex);
		}

		#endregion

		/// <summary>
		/// This method will check the internet connection state.
		/// </summary>
		/// <param name="connected"></param>
		/// <param name="reserved"></param>
		/// <returns>True if connected to the internet</returns>
		[DllImport("wininet.dll")]
		public static extern bool InternetGetConnectedState(ref uint connected, uint reserved);

		#endregion
	}
}